# -*- coding: utf-8 -*-
import hashlib
import json

import requests

from common.mch import db as mch_db
from common.order import db as order_db
from common.order.model import *
from common.utils import exceptions as err
from common.utils import track_logging

_LOGGER = track_logging.getLogger(__name__)


def generate_sign(mch_id, params):
    mch_account = mch_db.get_account(mch_id)
    if not mch_account:
        raise err.AuthenticateError('mch_id invalid')
    s = ''
    for k in sorted(params.keys()):
        s += '%s=%s&' % (k, params[k])
    s += 'key=%s' % mch_account.api_key
    m = hashlib.md5()
    m.update(s.encode('utf8'))
    sign = m.hexdigest().upper()
    return sign


def construct_notify_data(pay):
    discount = float(json.loads(pay.extend or '{}').get('discount', 0))
    total_fee = float(pay.total_fee) + discount
    data = {
        'trade_no': pay.id,
        'mch_id': pay.mch_id,
        'trade_type': pay.channel_type,
        'out_trade_no': pay.out_trade_no,
        'pay_result': pay.status,
        'total_fee': total_fee,
        'extra': pay.extra,
    }
    sign = generate_sign(pay.mch_id, data)
    data.update({'sign': sign})
    return data


def notify_mch(pay_id):
    """
    通知商户接口
    """
    pay = order_db.get_pay(pay_id)
    if pay.notify_status == NOTIFY_STATUS.SUCC:
        _LOGGER.warn('notify_mch, pay[%s] has been notified succ, notify again!', pay.id)
    notify_url = pay.notify_url
    # construct post data
    data = construct_notify_data(pay)
    try:
        res = requests.post(notify_url, data=data, timeout=5)
        if res.text == 'success':
            _LOGGER.info('async notify_mch[%s] succ for pay %s',
                         pay.mch_id, pay.id)
            pay = order_db.add_notify_success(pay.id)
            return True, pay
        else:
            _LOGGER.info('async notify_mch[%s] fail for pay %s,url: %s, data:%s, notify response %s',
                         pay.mch_id, pay.id, notify_url, json.dumps(data), res.text)
    except requests.exceptions.Timeout as e:
        _LOGGER.warn('async notify_mch, requests timeout for pay %s, err:%s', pay.id, e)
    except requests.exceptions.RequestException as e:
        _LOGGER.warn('async notify_mch, requests error for pay %s, err:%s', pay.id, e)
    except Exception as e:
        _LOGGER.exception('async notify_mch[%s] exception for pay %s',
                          pay.mch_id, pay.id)
    pay = order_db.add_notify_fail(pay.id)
    return False, pay
